Почему за одну прогулку в Петербурге моя GPS-стратегия давала больше земли, чем в Москве
В начале мая я взял раннюю версию GeoConquest с собой в отпуск в Петербург.
Игра уже работала на настоящем GPS: можно было выйти со своей территории, оставить за собой след, замкнуть маршрут и захватить оказавшийся внутри участок реальной карты.
В Москве я протестировал эту механику и решил, что с сеткой всё в порядке.
Петербург довольно быстро доказал обратное.
Сначала я решил захватить город с теплохода
План казался прекрасным: сесть на прогулочный теплоход, проплыть по рекам и каналам и оставить за собой огромный след через центр Петербурга.
На практике всё закончилось примерно у первых мостов.
Под ними мой телефон начал терять GPS. В маршруте появились разрывы, а вскоре след оборвался окончательно. Надежду захватить половину города, лениво сидя на палубе, пришлось оставить.
На скриншоте ещё используется OpenStreetMap. На Яндекс Карты игра переехала значительно позже.
Зато этот кадр точно показывает возраст версии: он сделан 5 мая, примерно за неделю до одной из самых больших переделок всей игры.
Тогда я пошёл захватывать «Газпром»
Следующей целью стал Лахта Центр, где находится центральный офис «Газпрома».
Сначала я почти замкнул маршрут вокруг здания.
А ещё через несколько секунд Лахта Центр уже целиком находился внутри моей территории.
К сожалению, с тех пор перед публичным релизом я делал вайп, так что сейчас территория вновь свободная - your's for the taking! (а вообще в игре вайпов нет)
После этого я поднялся на экскурсии на 83-й и 86-й этажи. Получилась довольно полная программа посещения: сначала захватить небоскрёб на карте, затем посмотреть с него на город сверху.
Но именно во время петербургских прогулок я начал замечать странность.
За одинаковое пройденное расстояние игра выдавала здесь больше гексов, чем в Москве.
Я хотел сделать гексы размером 30 метров
Первую географическую сетку я написал самостоятельно.
Внутри игры каждый гекс имел обычные координаты q,r. Я накладывал эту бесконечную сетку на проекцию карты и задавал клеткам фиксированный размер: 30 метров от одной плоской стороны до другой.
Звучит логично. Метр в Москве должен быть таким же метром в Петербурге, Африке или Австралии.
Но карта Земли не является самой Землёй.
Для отображения мира использовалась проекция Меркатора. Чем дальше от экватора, тем сильнее она растягивает поверхность на экране. Моя сетка оставалась одинаковой в координатах проекции, но её реальный размер на земле менялся вместе с широтой.
У экватора условный 30-метровый гекс действительно занимал примерно 30 метров.
В Москве его реальный размер уменьшался примерно до 17 метров.
В Петербурге — уже примерно до 15.
Получалось, что за одно и то же расстояние петербургский игрок мог пересечь примерно на 12% больше гексов, чем московский. А игроку ближе к экватору пришлось бы ходить почти вдвое больше.
География сломала игровой баланс
В GeoConquest количество гексов — не просто визуальная условность.
За каждый гекс игрок получает опыт движения. Гексами измеряется площадь захвата, размер владений, задания и активность клана. Чем мельче клетки в конкретном городе, тем быстрее там можно было развиваться.
Петербург получал преимущество перед Москвой.
Москва получала огромное преимущество перед Сингапуром.
А на совсем высоких широтах сетка продолжала бы сжиматься ещё сильнее.
Для обычной карты такое искажение терпимо: пользователю важно увидеть улицы и построить маршрут. Но для игры, в которой сама поверхность карты является общим соревновательным полем, это превращалось в фундаментальную несправедливость.
Нельзя делать всемирную стратегию, в которой сложность зависит от широты города.
Исправить одну формулу не получилось
Первой мыслью было просто компенсировать масштаб проекции через широту.
Но тогда начинали расползаться остальные части системы.
Клиент самостоятельно рассчитывал форму каждого гекса. Сервер хранил территории под идентификаторами вроде -7442,332795. По этим же координатам вычислялись соседи, расстояния, маршруты, видимая область и захваты.
Для отдаления карты я уже построил несколько уровней детализации: маленькие клетки объединялись в более крупные, чтобы показать территорию города, страны или континента.
Все эти системы предполагали, что мир является одной идеально регулярной плоской сеткой.
Можно было продолжать чинить её по частям. Добавить поправку на широту, отдельно исправить отрисовку, придумать новые правила для соседей и переделать уровни детализации.
Но чем дальше я смотрел, тем яснее становилось: проблема находилась в самой основе.
Выбор пал на H3
Вместо собственной сетки я решил использовать H3 — географическую систему, которая делит поверхность Земли на иерархию вложенных ячеек.
Она изначально предназначена для работы с глобальными координатами. Для любой точки можно получить идентификатор ячейки, её границы, соседей и родительскую клетку более крупного уровня.
Самое важное: размеры ячеек остаются сопоставимыми в разных частях планеты. Они не уменьшаются систематически при движении от экватора к полюсам только из-за проекции карты.
На плоском изображении всё выглядит даже немного парадоксально: северные гексы кажутся крупнее южных. Но это карта растягивается к полюсам, а не реальные ячейки на поверхности Земли.
Заодно H3 уже имела готовую вложенность. Мелкие игровые ячейки можно объединять в более крупные родительские и показывать на разных уровнях масштаба.
Это заменяло значительную часть моей самодельной системы отображения мира.
А потом начался страшный рефакторинг
Перейти на H3 означало не поменять одну библиотеку, а заменить язык, на котором вся игра описывала карту.
У старого гекса были две числовые координаты: q и r.
У нового появился непрозрачный H3-идентификатор. Его границы больше нельзя было самостоятельно восстановить простой формулой на клиенте. Даже форма ячеек могла немного различаться, а среди обычных шестиугольников на планете существуют специальные пятиугольные ячейки.
Пришлось переделать почти всё:
преобразование GPS-координат в игровую клетку;
хранение территорий и следов;
поиск соседних гексов;
расчёт расстояния;
движение игроков и тестовых ботов;
заполнение области внутри маршрута;
отрисовку границ на клиенте;
загрузку территорий вокруг игрока;
уровни детализации на дальнем масштабе;
тесты, которые раньше оперировали координатами q,r.
Геометрию я перенёс на сервер. Теперь именно сервер сообщает клиенту центр и настоящие границы каждой ячейки, а клиент только отображает полученные данные.
Старую тестовую карту пришлось очистить: прежние идентификаторы территорий не имели честного взаимно однозначного соответствия новым H3-ячейкам.
В одном основном коммите изменились 24 файла, добавилась примерно тысяча строк и удалилось больше двухсот. Но реальный объём работы был больше: до этого я несколько дней выстраивал границу между старой сеткой и остальной игрой, чтобы не менять всё одновременно.
Гексы стали немного менее красивыми, но игра — честнее
На идеальной плоской сетке каждый шестиугольник выглядит совершенно одинаково.
H3 покрывает не плоскость, а почти сферическую Землю. Поэтому ячейки могут быть слегка вытянутыми, а их форма и площадь не абсолютно идентичны по всей планете.
Но теперь это небольшие особенности глобальной географической системы, а не двукратная разница между экватором и северными городами.
Игроки в Петербурге больше не получают систематическое преимущество перед Москвой только из-за широты. Можно открыть игру в другой стране и рассчитывать на сопоставимый масштаб территории, движения и наград.
Через неделю после прогулки на теплоходе GeoConquest уже работала на H3.
Поэтому старые петербургские скриншоты для меня выглядят немного странно: на них ещё видна первая сетка, которая смогла пережить Москву, но не выдержала поездки в отпуск.
А вам что кажется важнее для игры на реальной карте: идеально одинаковая форма клеток на экране или максимально близкий физический размер по всему миру?
Играть можно прямо в телефонном браузере: https://geo.juju.ru
Версия для Google Play уже находится в internal testing, доступ можно получить здесь.
Патчноуты и история разработки: https://t.me/GeoConquest





























